package com.shb.jutils.commons;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class ZipUtil {
	private ZipUtil(){}
	
	/**
	 * 解压zip压缩文件
	 * @param zipFile	压缩文件路径
	 * @param outPath	解压路径
	 */
	public static void unZipFolder(String zipFile, String outPath){
		FileInputStream fis = null;
		FileOutputStream fos = null;
		ZipInputStream inZip = null;
		ZipEntry zipEntry;
		
		try {
			File outDir = new File(outPath);
			if(!outDir.exists() || !outDir.isDirectory()){
				outDir.mkdirs();
			}
			
			fis = new FileInputStream(new File(zipFile));
			inZip = new ZipInputStream(fis);
			String szName = "";
			while((zipEntry = inZip.getNextEntry()) != null){
				szName = zipEntry.getName();
				if(zipEntry.isDirectory()){
					szName = szName.substring(0, szName.length() -1);
					File folder = new File(outPath + File.separator + szName);
					folder.mkdirs();
				}else {
					String fName = outPath + File.separator + szName;
					File file = new File(fName);
					
					File dir = new File(fName.substring(0, fName.lastIndexOf(File.separator)));
					if(!dir.exists() || !dir.isDirectory()){
						dir.mkdirs();
					}
					file.createNewFile();
					
					fos = new FileOutputStream(file);
					int len;
					byte[] buffer = new byte[1024];
					while((len = inZip.read(buffer)) != -1){
						fos.write(buffer, 0, len);
						fos.flush();
					}
					fos.close();
				}
			}
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}finally {
			if(inZip != null){
				try {
					inZip.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(fis != null){
				try {
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	/**
	 * 压缩文件或文件夹
	 * @param srcFile	文件夹或文件路径
	 * @param zipFile	zip文件的压缩路径
	 */
	public static void zipFolder(String srcFile, String zipFilePath){
		FileOutputStream fos = null;
		ZipOutputStream zos = null;
		try {
			fos = new FileOutputStream(new File(zipFilePath));
			zos = new ZipOutputStream(fos);
			File file = new File(srcFile);
			zipFiles(file.getParent() + File.separator, file.getName(), zos);
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		} finally{
			if(zos != null){
				try {
					zos.finish();
					zos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(fos != null){
				try {
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	/**
	 * 压缩文件或文件夹
	 * @param folderPath	文件所在的父级目录
	 * @param folderName	文件名
	 * @param zos			压缩流
	 */
	public static void zipFiles(String folderPath, String folderName, ZipOutputStream zos){
		File file = new File(folderPath + folderName);
		try{
			//目标是文件
			if(file.isFile()){
				ZipEntry zipEntry = new ZipEntry(folderName);
				FileInputStream fis = new FileInputStream(file);
				zos.putNextEntry(zipEntry);
				int len;
				byte[] buffer = new byte[4096];
				while((len = fis.read(buffer)) != -1){
					zos.write(buffer, 0, len);
				}
				fis.close();
				zos.closeEntry();
			}else {
				//文件夹
				String fileList[] = file.list();
				//文件夹为空
				if(fileList.length < 0){
					ZipEntry zipEntry =  new ZipEntry(folderName + File.separator);
					zos.putNextEntry(zipEntry);
					zos.closeEntry();
				}
				for(int i =0; i < fileList.length; i++){
					zipFiles(folderPath, folderName + File.separator + fileList[i], zos);
				}
			}
		}catch(IOException e){
			throw new RuntimeException(e);
		}
	}
	
	/**
     * 多文件压缩
     * @param fileList	文件集合
     * @param zipPath	zip路径
     */
	public static void zipFiles(List<File> fileList, String zipPath){
		FileOutputStream fos = null;
		ZipOutputStream zos = null;
		try{
			fos = new FileOutputStream(new File(zipPath));
			zos = new ZipOutputStream(fos);
			int len ;
			for(File f : fileList){
				if(f.exists() && f.isFile()){
					zos.putNextEntry(new ZipEntry(f.getName()));
					FileInputStream fis = new FileInputStream(f);
					byte[] buffer = new byte[4096];
					while((len = fis.read(buffer)) != -1){
						zos.write(buffer, 0, len);
					}
					fis.close();
					zos.closeEntry();
				}else {
					throw new RuntimeException("该方法不支持文件夹压缩！");
				}
			}
		}catch (IOException e){
			throw new RuntimeException(e);
		}finally{
			if(zos != null){
				try {
					zos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(fos != null){
				try {
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 获取压缩文件中某个压缩文件的流
	 * NOTE: 被压缩的文件不存在时,抛出NullPointerException
	 * @param zipPath	压缩文件路径
	 * @param file		被压缩的文件路径
	 * @return
	 */
	@SuppressWarnings("resource")
	public static InputStream inputStreamFromZip(String zipPath, String file){
		InputStream in = null;
		try {
			ZipFile zipFile = new ZipFile(zipPath);
			ZipEntry zipEntry = zipFile.getEntry(file);
			in = zipFile.getInputStream(zipEntry);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		return in;
	}
	
	/**
	 * 获取压缩文件夹中的文件和文件夹
	 * @param zipPath			压缩文件路径
	 * @param bContainFolder	是否包含文件夹
	 * @param bContainFile		是否包含文件
	 * @return
	 */
	public static List<File> GetFileList(String zipPath, boolean bContainFolder, boolean bContainFile){
		List<File> fileList = new ArrayList<File>();
		FileInputStream fis = null;
		ZipInputStream zis = null;
		ZipEntry zipEntry ;
		try {
			fis = new FileInputStream(new File(zipPath));
			zis = new ZipInputStream(fis);
			String szName;
			while((zipEntry = zis.getNextEntry()) != null){
				szName = zipEntry.getName();
				if(zipEntry.isDirectory()){
					if(bContainFolder){
						szName = szName.substring(0, szName.length()-1);
						File folder = new File(szName);
						fileList.add(folder);
					}
				}else {
					if(bContainFile){
						fileList.add(new File(szName));
					}
				}
			}
		} catch (FileNotFoundException e){
			throw new RuntimeException(e);
		} catch (IOException e) {
			throw new RuntimeException(e);
		} finally {
			if(zis != null){
				try {
					zis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(fis != null){
				try {
					fis.close();
				} catch (IOException e){
					e.printStackTrace();
				}
			}
		}
		return fileList;
	}	
}
